﻿using FellowOakDicom.Network;
using FellowOakDicom.Network.Client;
using LS.DicomViewer.Common;
using Microsoft.Win32;
using System;
using System.Collections.ObjectModel;
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;

namespace DicomSCUDemo
{
    public class FileItem : BindableObject<FileItem>
    {
        int _index = 0;
        public int Index
        {
            get => _index;
            set => SetProperty(ref _index, value);
        }

        string _name;

        public string Name
        {
            get => _name;
            set => SetProperty(ref _name, value);
        }

        string _filePath;

        public string FilePath
        {
            get => _filePath;
            set => SetProperty(ref _filePath, value);
        }

        bool? _isUpload;

        public bool? IsUpload
        {
            get => _isUpload;
            set => SetProperty(ref _isUpload, value);
        }

        string _remark;

        public string Remark
        {
            get => _remark;
            set => SetProperty(ref _remark, value);
        }
    }

    public class FileBatch : BindableObject<FileItem>
    {

        int _uploadCount = 0;

        public int UploadCount
        {
            get => _uploadCount;
            set => SetProperty(ref _uploadCount, value);
        }

        string _remark;

        public string Remark
        {
            get => _remark;
            set => SetProperty(ref _remark, value);
        }

        ObservableCollection<FileItem> fileItems = new ObservableCollection<FileItem>();
        public ObservableCollection<FileItem> Files
        {
            get => fileItems;
            set => SetProperty(ref fileItems, value);
        }
    }

    public class DicomUploadViewModel : BindableObject<DicomUploadViewModel>
    {
        ObservableCollection<FileBatch> fileBatches = new ObservableCollection<FileBatch>();

        public ObservableCollection<FileBatch> FileBatches
        {
            get => fileBatches;
            set => SetProperty(ref fileBatches, value);
        }

        string _ip;

        public string Ip
        {
            get => _ip;
            set => SetProperty<string>(ref _ip, value);
        }

        int _port = 60000;

        public int Port
        {
            get => _port;
            set => SetProperty(ref _port, value);
        }

        string _aet;

        public string Aet
        {
            get => _aet;
            set=>SetProperty(ref _aet, value);
        }

        bool isRunning;

        public bool IsRunning
        {
            get => isRunning;
            set => SetProperty(ref isRunning, value);
        }
        int totalUploadCount;

        public int TotalUploadCount
        {
            get => totalUploadCount;
            set => SetProperty(ref totalUploadCount, value);
        }

        int totalCount;

        public int TotalCount
        {
            get => totalCount;
            set => SetProperty(ref totalCount, value);
        }
        public Action<string> Message { get; set; }

        public void SelectFiles()
        {
            var dialog = new OpenFileDialog();
            dialog.Multiselect = true;
            dialog.Filter = "Dicom文件|*.dcm";
            if (dialog.ShowDialog() == true)
            {
                var info = new FileBatch();
                foreach (var f in dialog.FileNames)
                {
                    if (FileBatches.Any(p => p.Files.Any(t => t.FilePath == f))) continue;
                    info.Files.Add(new FileItem { FilePath = f, Name = Path.GetFileName(f), IsUpload = false, Index = info.Files.Count });
                }
                if (info.Files.Count > 0)
                {
                    FileBatches.Add(info);
                }
                TotalUploadCount = 0;
            }
        }

        public void Start()
        {
            if (isRunning) return;
            if (string.IsNullOrWhiteSpace(Ip) || string.IsNullOrWhiteSpace(Aet)) return;    
            IsRunning = true;
            SaveConfig();
            TotalCount = FileBatches.Sum(p => p.Files.Count);
            var result = Parallel.ForEach(FileBatches, (p, state, i) =>
            {
                Upload(p);
            });
            Task.Run(() =>
            {
                while (FileBatches.Any(p => p.Files.Any(t => t.IsUpload != true))) ;
                IsRunning = false;
            });
        }

        public void ReStart()
        {
            IsRunning = false;
            if (isRunning) return;
            if (string.IsNullOrWhiteSpace(Ip) || string.IsNullOrWhiteSpace(Aet)) return;
            SaveConfig();
            IsRunning = true;
            FileBatches.ToList().ForEach(a =>
            {
                a.Files.ToList().ForEach(t => t.IsUpload = false);
                a.Remark = null;
                a.UploadCount = 0;
            });
            var result = Parallel.ForEach(FileBatches, (p, state, i) =>
            {
                Upload(p);
            });
            Task.Run(() =>
            {
                while (FileBatches.Any(p => p.Files.Any(t => t.IsUpload != true))) ;
                IsRunning = false;
            });
        }

        void SaveConfig()
        {
            LS.Dicom.Tools.Properties.Settings.Default.IP = Ip;
            LS.Dicom.Tools.Properties.Settings.Default.AET = Aet;
            LS.Dicom.Tools.Properties.Settings.Default.Port = Port;
            LS.Dicom.Tools.Properties.Settings.Default.Save();
        }
        private async void Upload(FileBatch info)
        {           
            var client = DicomClientFactory.Create(Ip, Port, false, "SCU", Aet);
            client.ClientOptions.AssociationRequestTimeoutInMs = 5000;
            client.ServiceOptions.RequestTimeout = TimeSpan.FromMinutes(1);
            while (IsRunning)
            {
                await client.AddRequestAsync(new DicomCEchoRequest
                {
                    OnResponseReceived = (a, b) =>
                    {
                        if (b.Status.State != DicomState.Success)
                        {
                            info.Remark = "连接失败：准备重试" + b.Status.ErrorComment;
                        }
                    }
                });
                try
                {
                    await client.SendAsync();
                    break;
                }
                catch (Exception ex)
                {
                    info.Remark = "连接失败：准备重试" + ex.Message;
                    Thread.Sleep(2000);
                }
            }
            await Task.Delay(10);
            info.Remark = null;
            info.UploadCount = 0;
            var currentId = -1;
            while (isRunning && info.Files.Count(p => p.IsUpload != true) > 0)
            {
                var fileItem = info.Files.FirstOrDefault(p => p.Index != currentId && p.IsUpload != true);
                fileItem.Remark = null;
                while (IsRunning)
                {
                    await client.AddRequestAsync(new DicomCEchoRequest
                    {
                        OnResponseReceived = (a, b) =>
                        {
                            if (b.Status.State != DicomState.Success)
                            {
                                info.Remark = "连接失败：准备重试" + b.Status.ErrorComment;
                            }
                        }
                    });
                    try
                    {
                        await client.SendAsync();
                        break;
                    }
                    catch (Exception ex)
                    {
                        info.Remark = "连接失败：准备重试：" + ex.Message;
                        Thread.Sleep(2000);
                    }
                }

                await client.AddRequestAsync(new DicomCStoreRequest(fileItem.FilePath)
                {
                    OnResponseReceived = async (req, response) =>
                    {
                        if (response.Status == DicomStatus.Success)
                        {
                            fileItem.IsUpload = true;
                            fileItem.Remark = null;
                            lock (info)
                            {
                                info.UploadCount++;
                                info.Remark = $"共上传了 {info.UploadCount}/{info.Files.Count} 个文件";
                                TotalUploadCount = FileBatches.Sum(p => p.Files.Count(t => t.IsUpload == true));
                            }
                        }
                        else
                        {
                            fileItem.Remark = $"上传出错:{response.Status.ErrorComment}---准备重试";
                        }
                    }
                });
                currentId = fileItem.Index;
                try
                {
                    await client.SendAsync();
                    await Task.Delay(10);
                }
                catch (Exception ex)
                {
                    fileItem.Remark = $"上传出错:{ex.Message}---准备重试";
                }
            }
            client = null;
        }

        public void Stop()
        {
            IsRunning = false;
        }

        public void Clear()
        {
            Stop();
            FileBatches = new ObservableCollection<FileBatch>();
        }
    }
}
